/*
 * ManejadorArchivoClasificacion.cpp
 *
 *  Created on: 10/09/2010
 *      Author: julfc
 */

#include "ManejadorArchivoClasificacion.h"

ManejadorArchivoClasificacion::ManejadorArchivoClasificacion(char* nombreArchivo, AbrirCrearArchivo abrirCrear):
											ManejadorAccesoDatos(nombreArchivo, abrirCrear) {
}

vector<long> ManejadorArchivoClasificacion::leerListaDeMails(long nroBloque, long id) {

	char* bloque = leerBloque(nroBloque);
	char* auxBloque = bloque;
	long cantListas = 0;
	bool encontrado = false;
	vector<long> lista;

	auxBloque = bloque;
	memcpy(&cantListas, auxBloque, sizeof(long));
	//Me salteo el espacio libre en el bloque.
	auxBloque+=2*sizeof(long);

	long i = 1;

	while (i <= cantListas && !encontrado) {
		long uiAux = 0;
		long tamanioLista = 0;

		memcpy(&uiAux, auxBloque, sizeof(long));
		auxBloque+=sizeof(long);
		memcpy(&tamanioLista, auxBloque, sizeof(long));
		auxBloque+=sizeof(long);

		if (uiAux == id ) {
			encontrado = true;
			long cantidadIds = tamanioLista/sizeof(long);
			for (int j = 0; j<cantidadIds; j++) {
				long idInsert;
				memcpy(&idInsert,auxBloque,sizeof(long));
				auxBloque+=sizeof(long);
				lista.push_back(idInsert);
			}
		} else {
			auxBloque+= tamanioLista;
			i++;
		}
	}
	free(bloque);
	return lista;
}

long ManejadorArchivoClasificacion::escribirListaDemails(long id, vector<long> lista) {
	long tamLista = sizeof(long) * lista.size();
	long tamVector = lista.size();
	long tamBloque = getTamanioBloques();
	long tamMaximoListaEnBloque = tamBloque - 4*sizeof(long);
	if (tamLista > tamMaximoListaEnBloque) {
	  tamVector = tamMaximoListaEnBloque/sizeof(long);
	  tamLista = tamVector * sizeof(long);
	  cout << " \n\n Se trunco la lista porque no entra en el bloque, la lista es de " << tamVector << "\n\n";
	}

	long espLibreBloque = 0;
	long cantListas = 0;
	char* bloque;
	char* auxBloque;

	long nroBloque = buscarEspacioEnBloques(tamLista);
	if (nroBloque < 0) {
		//Tengo que creabloquer un bloque nuevo
		nroBloque = getCantidadBloques();
		//cout << " \n\n No hay espacio libre en el bloque, se creo el bloque " << nroBloque << "\n\n";

		bloque = inicillizarBloque(tamBloque);
		auxBloque = bloque;
		//Guardo espacio libre (total - cant listas - esp_libre - id de la lista - cantidad de reg en lista - tam de la lista)).
		espLibreBloque = tamBloque - 4*sizeof(long) - tamLista;
		cantListas = 1;
		memcpy(auxBloque, &cantListas, sizeof(long));
		auxBloque+=sizeof(long);
		memcpy(auxBloque, &espLibreBloque, sizeof(long));
		auxBloque+=sizeof(long);
	} else {
		//cout << " \n\n Hay espacio libre en el bloque " << nroBloque << "\n\n";
		bloque = leerBloque(nroBloque);
		auxBloque = bloque;
		memcpy(&cantListas, auxBloque, sizeof(long));
		cantListas++;
		memcpy(auxBloque, &cantListas, sizeof(long));
		auxBloque+=sizeof(long);
		memcpy(&espLibreBloque, auxBloque, sizeof(long));
		long index = tamBloque - espLibreBloque;
		espLibreBloque = espLibreBloque - tamLista - (2*sizeof(long));
		memcpy(auxBloque, &espLibreBloque, sizeof(long));
		auxBloque = bloque;
		auxBloque+= index;
	}
	memcpy(auxBloque, &id, sizeof(long));
	auxBloque+=sizeof(long);
	memcpy(auxBloque, &tamLista, sizeof(long));
	auxBloque+=sizeof(long);
	for (int i = 0; i < tamVector; i++) {
		memcpy(auxBloque, &lista[i], sizeof(long));
		auxBloque+=sizeof(long);
	}
	escribir(bloque, nroBloque);
	free(bloque);
	return nroBloque;
}

bool ManejadorArchivoClasificacion::eliminarIdDeLista(long id) {
	long cantBloques = getCantidadBloques();
	for (int i = 0; i < cantBloques; i++) {
		eliminarIdDeBloque(i, id);
	}
	return true;
}

bool ManejadorArchivoClasificacion::eliminarIdDeBloque(long nroBloque, long id) {
	char* bloque = leerBloque(nroBloque);
	long tamBloque = getTamanioBloques();
	char* auxBloque = bloque;
	long cantListas = 0;
	long espLibreBloque = 0;
	long i = 0;
	long uiAux = 0;
	long tamanioLista = 0;
	long index = 0;
	bool estaElId = false;
	bool seModifico = false;

	memcpy(&cantListas, auxBloque, sizeof(long));
	auxBloque+= sizeof(long);
	memcpy(&espLibreBloque, auxBloque, sizeof(long));
	auxBloque+= sizeof(long);

	index+= 2*sizeof(long);
	char* aGuardar;

	while (i < cantListas) {
		vector<long> lista;
		estaElId = false;
		uiAux = 0;
		tamanioLista = 0;
		memcpy(&uiAux, auxBloque, sizeof(long));
		auxBloque+=sizeof(long);
		memcpy(&tamanioLista, auxBloque, sizeof(long));
		auxBloque+=sizeof(long);
		index+= 2*sizeof(long);
		//Obtengo la lista acomodo el bloque y la vuelvo a insertar.
		long cantidadIds = tamanioLista/sizeof(long);
		for (int j = 0; j<cantidadIds; j++) {
			long idInsert;
			memcpy(&idInsert,auxBloque,sizeof(long));
			auxBloque+=sizeof(long);
			if (idInsert == id) {
				estaElId = true;
				seModifico = true;
			} else {
				lista.push_back(idInsert);
			}
			index+=sizeof(long);
		}
		if (estaElId) {
			//actualizarListaDemails()
			char* nuevoBloque = inicillizarBloque(tamBloque);
			char* auxNuevoBloque = nuevoBloque;
			index-= 2*sizeof(long);
			index-=  tamanioLista;
			//Copio el cont. del nodo hasta antes de la lista a sacar para actualizar.
			auxBloque = bloque;
			//Salteo cantidad de listas en bloque.
			auxBloque+= sizeof(long);
			memcpy(&espLibreBloque, auxBloque, sizeof(long));
			//Solo sumo un sizeof(long) al espacio libre.
			espLibreBloque = espLibreBloque + sizeof(long);
			memcpy(auxBloque, &espLibreBloque, sizeof(long));
			//Vuelvo al principio del bloque.
			auxBloque-= sizeof(long);
			memcpy(auxNuevoBloque, auxBloque, index);
			auxNuevoBloque+= index;
			//Guardo de nuevo la lista sin el id que elimine.
			long nuevoTamLista = lista.size()*sizeof(long);
			memcpy(auxNuevoBloque, &uiAux, sizeof(long));
			auxNuevoBloque+=sizeof(long);
			memcpy(auxNuevoBloque, &nuevoTamLista, sizeof(long));
			auxNuevoBloque+=sizeof(long);
			for (unsigned int k = 0; k < lista.size(); k++) {
				memcpy(auxNuevoBloque, &lista[k], sizeof(long));
				auxNuevoBloque+=sizeof(long);
			}
			//Copio el resto de las cosas que habia en el bloque.
			auxBloque+= index + 2*sizeof(long) + tamanioLista;
			memcpy(auxNuevoBloque, auxBloque, tamBloque - index - 2*sizeof(long) - tamanioLista);
			//Escribo el nodo sin la lista.
			index+= 2*sizeof(long)+nuevoTamLista;
			free(bloque);
			bloque = nuevoBloque;
			auxBloque = auxNuevoBloque;
			aGuardar = bloque;
			i++;
		} else {
			i++;
		}
	}
	if(seModifico) {
		escribir(aGuardar, nroBloque);
		free(aGuardar);
	}
	return seModifico;
}

long ManejadorArchivoClasificacion::actualizarListaDemails(long id, long nroBloque, long claveParaAgregar) {
	char* bloque = leerBloque(nroBloque);
	long tamBloque = getTamanioBloques();
	long tamMaximoListaEnBloque = tamBloque - 4*sizeof(long);
	char* auxBloque = bloque;
	long nuevoNroBloque = -1;
	long cantListas = 0;
	long espLibreBloque = 0;
	bool encontrado = false;
	bool noEntraEnBloque = false;
	vector<long> lista;
	long i = 0;
	long uiAux = 0;
	long tamanioLista = 0;
	long index = 0;

	memcpy(&cantListas, auxBloque, sizeof(long));
	auxBloque+= sizeof(long);
	memcpy(&espLibreBloque, auxBloque, sizeof(long));
	auxBloque+= sizeof(long);

	index+= 2*sizeof(long);

	while (i <= cantListas && !encontrado) {
		uiAux = 0;
		tamanioLista = 0;
		memcpy(&uiAux, auxBloque, sizeof(long));
		auxBloque+=sizeof(long);
		memcpy(&tamanioLista, auxBloque, sizeof(long));
		auxBloque+=sizeof(long);
		index+= 2*sizeof(long);
		//Obtengo la lista acomodo el bloque y la vuelvo a insertar.
		if (uiAux == id ) {
		  encontrado = true;
		  if (tamMaximoListaEnBloque <= (tamanioLista + sizeof(long))) {
		    noEntraEnBloque = true;
		  } else {
		    long cantidadIds = tamanioLista/sizeof(long);
		    for (int j = 0; j<cantidadIds; j++) {
		      long idInsert;
		      memcpy(&idInsert,auxBloque,sizeof(long));
		      auxBloque+=sizeof(long);
		      lista.push_back(idInsert);
		      index+=sizeof(long);
		    }
		    lista.push_back(claveParaAgregar);
		  }
		} else {
			auxBloque+= tamanioLista;
			index+= tamanioLista;
			i++;
		}
	}
	//Si en encuentro el vector lo saco de la lista.
	if (encontrado && !noEntraEnBloque) {
		char* nuevoBloque = inicillizarBloque(tamBloque);
		char* auxNuevoBloque = nuevoBloque;
		index-= 2*sizeof(long);
		index-=  tamanioLista;
		//Copio el cont. del nodo hasta antes de la lista a sacar para actualizar.
		auxBloque = bloque;

		memcpy(&cantListas, auxBloque, sizeof(long));
		cantListas--;
		memcpy(auxBloque, &cantListas, sizeof(long));
		auxBloque+= sizeof(long);
		memcpy(&espLibreBloque, auxBloque, sizeof(long));
		espLibreBloque = espLibreBloque + 2*sizeof(long) + tamanioLista;
		memcpy(auxBloque, &espLibreBloque, sizeof(long));

		//Vuelvo al principio del bloque.
		auxBloque-= sizeof(long);
		memcpy(auxNuevoBloque, auxBloque, index);
		auxBloque+= index + 2*sizeof(long) + tamanioLista;
		auxNuevoBloque+= index;
		memcpy(auxNuevoBloque, auxBloque, tamBloque - index - 2*sizeof(long) - tamanioLista);
		//Escribo el nodo sin la lista.
		escribir(nuevoBloque, nroBloque);
		nuevoNroBloque = escribirListaDemails(id, lista);
		free(nuevoBloque);
	}
	free(bloque);
	return nuevoNroBloque;
}

ManejadorArchivoClasificacion::~ManejadorArchivoClasificacion() {

}
